package service

import (
	"bufio"
	"fmt"
	"github.com/duke-git/lancet/v2/slice"
	log "github.com/sirupsen/logrus"
	"os/exec"
	"strconv"
	"strings"
	"usbipproxy/common"
	"usbipproxy/domain/vo"
)

type DeviceLinuxService struct {
	cache DeviceCacheService
}

/*
root@shengsuan-pc:/home/zxf# lsusb -v -d 1c4f:0027

Bus 005 Device 004: ID 1c4f:0027 SiGma Micro USB Keyboard
Device Descriptor:

	bLength                18
	bDescriptorType         1
	bcdUSB               1.10
	bDeviceClass            0
	bDeviceSubClass         0
	bDeviceProtocol         0
	bMaxPacketSize0         8
	idVendor           0x1c4f SiGma Micro
	idProduct          0x0027
	bcdDevice            1.16
	iManufacturer           1 SIGMACHIP
	iProduct                2 USB Keyboard
	iSerial                 0
	bNumConfigurations      1
	Configuration Descriptor:
	  bLength                 9
	  bDescriptorType         2
	  wTotalLength       0x003b
	  bNumInterfaces          2
	  bConfigurationValue     1
	  iConfiguration          0
	  bmAttributes         0xa0
	    (Bus Powered)
	    Remote Wakeup
	  MaxPower               98mA
	  Interface Descriptor:
	    bLength                 9
	    bDescriptorType         4
	    bInterfaceNumber        0
	    bAlternateSetting       0
	    bNumEndpoints           1
	    bInterfaceClass         3 Human Interface Device
	    bInterfaceSubClass      1 Boot Interface Subclass
	    bInterfaceProtocol      1 Keyboard
	    iInterface              0
	      HID Device Descriptor:
	        bLength                 9
	        bDescriptorType        33
	        bcdHID               1.10
	        bCountryCode            0 Not supported
	        bNumDescriptors         1
	        bDescriptorType        34 Report
	        wDescriptorLength      54
	       Report Descriptors:
	         ** UNAVAILABLE **
	    Endpoint Descriptor:
	      bLength                 7
	      bDescriptorType         5
	      bEndpointAddress     0x81  EP 1 IN
	      bmAttributes            3
	        Transfer Type            Interrupt
	        Synch Type               None
	        Usage Type               Data
	      wMaxPacketSize     0x0008  1x 8 bytes
	      bInterval              10
	  Interface Descriptor:
	    bLength                 9
	    bDescriptorType         4
	    bInterfaceNumber        1
	    bAlternateSetting       0
	    bNumEndpoints           1
	    bInterfaceClass         3 Human Interface Device
	    bInterfaceSubClass      0
	    bInterfaceProtocol      0
	    iInterface              0
	      HID Device Descriptor:
	        bLength                 9
	        bDescriptorType        33
	        bcdHID               1.10
	        bCountryCode            0 Not supported
	        bNumDescriptors         1
	        bDescriptorType        34 Report
	        wDescriptorLength      50
	       Report Descriptors:
	         ** UNAVAILABLE **
	    Endpoint Descriptor:
	      bLength                 7
	      bDescriptorType         5
	      bEndpointAddress     0x82  EP 2 IN
	      bmAttributes            3
	        Transfer Type            Interrupt
	        Synch Type               None
	        Usage Type               Data
	      wMaxPacketSize     0x0003  1x 3 bytes
	      bInterval              10

Device Status:     0x0000

	(Bus Powered)
*/

/*

接口类别 bInterfaceClass
0x01	Audio	音频设备（如麦克风、扬声器）
0x02	Communications	通信设备（如调制解调器）
0x03	Human Interface Device (HID)	人机接口设备（键盘、鼠标等）
0x08	Mass Storage	大容量存储设备（U盘、移动硬盘）
0x09	Hub	USB集线器
0x0A	CDC-Data	通信设备数据类
0x0E	Video	视频设备（摄像头）
0xE0	Wireless Controller	无线控制器（蓝牙、WiFi适配器）
0xFF	Vendor Specific	厂商自定义设备


接口子类 bInterfaceSubClass
0x00	无子类	未指定
0x01	Boot Interface	引导接口（BIOS/UEFI可识别的设备）
其他	保留	通常为0

 接口协议（bInterfaceProtocol
协议代码	描述	说明
0x00	无协议	未指定
0x01	键盘	引导接口键盘
0x02	鼠标 引导接口鼠标
其他	保留	如游戏手柄等
*/

// lsusb -v -d 1c4f:0027
func (d *DeviceLinuxService) GetDeviceInfo(vid, pid string) []*vo.DeviceInfo {

	cacheInfo := d.cache.GetDeviceInfo(vid, pid)
	if len(cacheInfo) > 0 {
		return cacheInfo
	}

	usbDevice, err := parseUSBDevice(vid, pid)
	if err != nil {
		log.Error(err)
		return nil
	}

	//log.Println(devices)
	var ret vo.DeviceInfo
	ret.Vid = vid
	ret.Pid = pid

	if usbDevice != nil {
		product := usbDevice.Product
		var pnpClass string
		var interProducts []string
		for _, item := range usbDevice.Configurations {
			for _, info := range item.Interfaces {
				interProducts = append(interProducts, info.ClassDesc+" "+info.ProtocolDesc)
				if info.SubClass > 0 && info.Protocol > 0 {
					pnpClass = common.GetPnpSubInterfaceProtocol(info.Protocol)
				} else {
					if pnpClass != common.PnpClassKeyboard && pnpClass != common.PnpClassMouse {
						pnpClass = common.GetPnpClassInterfaceClass(info.Class)
					}
				}
			}
		}
		if len(interProducts) > 0 {
			interProducts = slice.UniqueByComparator(interProducts, func(item string, other string) bool {
				return item == other
			})

			product = fmt.Sprintf("%s(%s)", product, strings.Join(interProducts, ","))
		}

		if pnpClass == "" {
			keys := []string{strings.ToLower(product), strings.ToLower(usbDevice.Manufacturer)}
			for _, key := range keys {
				if strings.Contains(key, "key") {
					continue
				}

				if d.cache.NeedUpanSkip(key) {
					continue
				}

				if strings.Contains(key, "storage") {
					pnpClass = common.PnpClassMassStorage
					break
				}
			}
		}
		ret.DeviceName = product
		ret.DeviceDesc = product
		ret.Manufacturer = usbDevice.Manufacturer
		ret.PnpClass = pnpClass
	}

	d.cache.SetDeviceInfo(vid, pid, []*vo.DeviceInfo{&ret})

	return []*vo.DeviceInfo{&ret}
}

func NewDeviceLinuxService(upanSkipWord string) DeviceService {
	return &DeviceLinuxService{
		cache: NewDeviceCacheServiceImpl(upanSkipWord),
	}
}

// 解析USB设备信息
func parseUSBDevice(vid, pid string) (*vo.USBDevice, error) {
	cmd := exec.Command("lsusb", "-v", "-d", vid+":"+pid)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("命令执行失败: %v\n%s", err, string(out))
	}

	log.Debugf("out vid:pid %s:%s out:%s", vid, pid, string(out))
	//log.Debugf("out vid:pid %s:%s", vid, pid)
	return parseLSUSBOutput(string(out)), nil
}

func parseLSUSBOutput(output string) *vo.USBDevice {
	device := &vo.USBDevice{}
	scanner := bufio.NewScanner(strings.NewReader(output))

	var currentConfig *vo.Configuration
	var currentInterface *vo.Interface
	var currentEndpoint *vo.Endpoint

	for scanner.Scan() {
		line := scanner.Text()
		trimmed := strings.TrimSpace(line)

		if trimmed == "" {
			continue
		}

		parts := strings.Fields(trimmed)
		if len(parts) < 2 {
			continue
		}
		key := parts[0]

		switch key {
		case "idVendor":
			if len(parts) > 1 {
				device.VendorID = strings.TrimPrefix(parts[1], "0x")
			}

		case "idProduct":
			if len(parts) > 1 {
				device.ProductID = strings.TrimPrefix(parts[1], "0x")
			}

		case "iManufacturer":
			if len(parts) >= 3 && parts[1] != "0" {
				device.Manufacturer = strings.Join(parts[2:], " ")
			}

		case "iProduct":
			if len(parts) >= 3 && parts[1] != "0" {
				device.Product = strings.Join(parts[2:], " ")
			}

		case "Configuration":
			// 创建新的配置
			newConfig := vo.Configuration{}
			device.Configurations = append(device.Configurations, newConfig)
			currentConfig = &device.Configurations[len(device.Configurations)-1]
			currentInterface = nil
			currentEndpoint = nil

		case "Interface":
			// 创建新的接口
			if currentConfig != nil {
				newInterface := vo.Interface{}
				currentConfig.Interfaces = append(currentConfig.Interfaces, newInterface)
				currentInterface = &currentConfig.Interfaces[len(currentConfig.Interfaces)-1]
				currentEndpoint = nil
			}

		case "bInterfaceNumber":
			if currentInterface != nil && len(parts) > 1 {
				if num, err := strconv.Atoi(parts[1]); err == nil {
					currentInterface.Number = num
				}
			}

		case "bInterfaceClass":
			if currentInterface != nil && len(parts) > 1 {
				if num, err := strconv.Atoi(parts[1]); err == nil {
					currentInterface.Class = num
				}
				if len(parts) > 2 {
					currentInterface.ClassDesc = strings.Join(parts[2:], " ")
				}
			}

		case "bInterfaceProtocol":
			if currentInterface != nil && len(parts) > 1 {
				if num, err := strconv.Atoi(parts[1]); err == nil {
					currentInterface.Protocol = num
				}
				if len(parts) > 2 {
					currentInterface.ProtocolDesc = strings.Join(parts[2:], " ")
				}
			}

		case "bInterfaceSubClass":
			if currentInterface != nil && len(parts) > 1 {
				if num, err := strconv.Atoi(parts[1]); err == nil {
					currentInterface.SubClass = num
				}
			}

		case "Endpoint":
			// 创建新的端点
			if currentInterface != nil {
				newEndpoint := vo.Endpoint{}
				currentInterface.Endpoints = append(currentInterface.Endpoints, newEndpoint)
				currentEndpoint = &currentInterface.Endpoints[len(currentInterface.Endpoints)-1]
			}

		case "bEndpointAddress":
			if currentEndpoint != nil && len(parts) > 1 {
				currentEndpoint.Address = parts[1]
				if strings.Contains(currentEndpoint.Address, "IN") {
					currentEndpoint.Direction = "IN"
				} else if strings.Contains(currentEndpoint.Address, "OUT") {
					currentEndpoint.Direction = "OUT"
				}
			}

		case "Transfer":
			if currentEndpoint != nil && len(parts) > 2 {
				currentEndpoint.TransferType = parts[2]
			}
		}
	}

	return device
}

/*
func main() {
	if len(os.Args) < 3 {
		fmt.Println("请提供 VID 和 PID (例如: 1c4f 0027)")
		return
	}

	vid := os.Args[1]
	pid := os.Args[2]

	device, err := parseUSBDevice(vid, pid)
	if err != nil {
		fmt.Println("错误:", err)
		return
	}

	printDeviceInfo(device)
}
*/

func printDeviceInfo(device *vo.USBDevice) {
	fmt.Printf("设备信息:\n")
	fmt.Printf("  厂商: %s\n", device.Manufacturer)
	fmt.Printf("  产品: %s\n", device.Product)
	fmt.Printf("  VID: %s\n", device.VendorID)
	fmt.Printf("  PID: %s\n", device.ProductID)

	for i, config := range device.Configurations {
		fmt.Printf("\n配置 #%d (%d 个接口):\n", i+1, len(config.Interfaces))

		for _, intf := range config.Interfaces {
			fmt.Printf("  接口 #%d: ", intf.Number)

			// 识别设备类型
			switch {
			case intf.Class == 3 && intf.Protocol == 1:
				fmt.Printf("键盘")
			case intf.Class == 3 && intf.Protocol == 2:
				fmt.Printf("鼠标")
			case intf.Class == 8:
				fmt.Printf("存储设备")
			default:
				if intf.Class == 3 {
					fmt.Printf("通用HID设备")
				} else {
					fmt.Printf("未知设备类型")
				}
			}

			fmt.Printf("\n")

			fmt.Printf("    |- 类别: %d (%s)\n", intf.Class, intf.ClassDesc)
			fmt.Printf("    |- 子类: %d\n", intf.SubClass)
			fmt.Printf("    |- 协议: %d (%s)\n", intf.Protocol, intf.ProtocolDesc)

			for j, ep := range intf.Endpoints {
				fmt.Printf("    |- 端点 #%d: %s (%s传输)\n", j+1, ep.Address, ep.TransferType)
			}
		}
	}
}
